/**
 * Copyright (c) 2008,中企动力华南研发中心
 * All rights reserved.
 */
package com.ce.util.security;


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.regex.Pattern;

/**
 * 逻辑、功能相关描述:用于导出excel文件的公共类
 *
 * @author lixiandi  编写日期：2008-01-21
 */
public class PasswordAuthenticator {

	/**
     * Function:生成经过hashed的密码，这个密码将用16字节的salt来保护
	 * @param password
	 *            要加密的密码
	 * @param algorithm
	 *            加密的算法，如SHA-1,MD5
	 *
	 * @return 加密的密码
     * Create author:lixiandi
     * Create on:2008-01-21
     * Edit author:
     * Edit on:
     * Why:
     */
	public static String createPassword(String password, String algorithm) throws Exception {

		String hashvalue = "";

		// 创建一个salt
		SecureRandom random = new SecureRandom();
		byte[] salt = new byte[12];
		random.nextBytes(salt);

		// 利用salt和password获取一个消息摘要。
		MessageDigest md = MessageDigest.getInstance(algorithm);
		md.update(salt);
		md.update(password.getBytes("UTF8"));
		byte[] digest = md.digest();
		byte[] digestWithSalt = new byte[digest.length + salt.length];

		// 将salt和digest的值赋予给igestWithSalt
		for (int k = 0; k < salt.length; k++) {
			digestWithSalt[k] = salt[k];
		}

		for (int j = 0; j < digest.length; j++) {
			digestWithSalt[salt.length + j] = digest[j];
		}

		// BASE64Encoder encoder = new BASE64Encoder();
		// 返回igestWithSalt，也就是返回经过salt和口令undate之后的值，我们可以把这个值放在数据库，以便以后检验。

		digestWithSalt = Sign.base64enc(digestWithSalt);
		hashvalue = new String(digestWithSalt);
		// 将hashvalue编码
		return hashvalue;
	}
	/**
     * Function:生成经过hashed的密码，这个密码将用16字节的salt来保护
	 * @param password
	 *            要加密的密码
	 * @return 加密的密码
     * Create author:lixiandi
     * Create on:2008-01-21
     * Edit author:
     * Edit on:
     * Why:
     */
	public static String createPassword(String password) throws Exception {

		String hashvalue = "";

		// 创建一个salt
		SecureRandom random = new SecureRandom();
		byte[] salt = new byte[12];
		random.nextBytes(salt);

		// 利用salt和password获取一个消息摘要。
		MessageDigest md = MessageDigest.getInstance("SHA-1");
		md.update(salt);
		md.update(password.getBytes("UTF8"));
		byte[] digest = md.digest();
		byte[] digestWithSalt = new byte[digest.length + salt.length];

		// 将salt和digest的值赋予给igestWithSalt
		for (int k = 0; k < salt.length; k++) {
			digestWithSalt[k] = salt[k];
		}

		for (int j = 0; j < digest.length; j++) {
			digestWithSalt[salt.length + j] = digest[j];
		}

		// BASE64Encoder encoder = new BASE64Encoder();
		// 返回igestWithSalt，也就是返回经过salt和口令undate之后的值，我们可以把这个值放在数据库，以便以后检验。

		digestWithSalt = Sign.base64enc(digestWithSalt);
		hashvalue = new String(digestWithSalt);
		// 将hashvalue编码
		return hashvalue;
	}

	/**
     * Function:检查密码和原来的密码是否匹配
	 * @param password
	 *            要校验的密码
	 * @param hashvalue
	 *            原来的密码，已经加密了
	 * @return 如果密码匹配返回true,否则返回false
	 *
     * Create author:lixiandi
     * Create on:2008-01-21
     * Edit author:
     * Edit on:
     * Why:
     */
	public static boolean authenticatePassword(String password, String hashvalue) throws Exception {

		boolean flag = false;
		// 将hashvalue解编码
		byte hashedPasswordWithSalt[] = hashvalue.getBytes();
		hashedPasswordWithSalt = Sign.base64dec(hashedPasswordWithSalt);
		byte[] salt = new byte[12];
		// 获取hashedPasswordWithSalt这里的salt值
		System.arraycopy(hashedPasswordWithSalt, 0, salt, 0, 12);

		// // 利用salt和password获取一个消息摘要。
		MessageDigest md = MessageDigest.getInstance("SHA-1");
		md.update(salt);
		md.update(password.getBytes("UTF8"));
		byte[] digest = md.digest();

		// 从ashedPasswordWithSalt截取除了salt部分的值，定义为digestWithSalt
		byte[] digestWithSalt = new byte[hashedPasswordWithSalt.length - 12];
		System.arraycopy(hashedPasswordWithSalt, 12, digestWithSalt, 0,
				hashedPasswordWithSalt.length - 12);

		// 比较digest和digestWithSalt

		if (Arrays.equals(digest, digestWithSalt)) {

			flag = true;

		} else {

			flag = false;

		}

		return flag;
	}
	/**
     * Function:检查密码和原来的密码是否匹配
	 * @param password
	 *            要校验的密码
	 * @param hashvalue
	 *            原来的密码，已经加密了
	 * @param algorithm
	 *            加密的算法，如SHA-1,MD5
	 * @return 如果密码匹配返回true,否则返回false
	 *
     * Create author:lixiandi
     * Create on:2008-01-21
     * Edit author:
     * Edit on:
     * Why:
     */
	public static boolean authenticatePassword(String password, String hashvalue,String algorithm)
			throws Exception {

		boolean flag = false;
		// 将hashvalue解编码
		byte hashedPasswordWithSalt[] = hashvalue.getBytes();
		hashedPasswordWithSalt = Sign.base64dec(hashedPasswordWithSalt);
		byte[] salt = new byte[12];
		// 获取hashedPasswordWithSalt这里的salt值
		System.arraycopy(hashedPasswordWithSalt, 0, salt, 0, 12);

		// //利用salt和password获取一个消息摘要。
		MessageDigest md = MessageDigest.getInstance(algorithm);
		md.update(salt);
		md.update(password.getBytes("UTF8"));
		byte[] digest = md.digest();

		// 从ashedPasswordWithSalt截取除了salt部分的值，定义为digestWithSalt
		byte[] digestWithSalt = new byte[hashedPasswordWithSalt.length - 12];
		System.arraycopy(hashedPasswordWithSalt, 12, digestWithSalt, 0,
				hashedPasswordWithSalt.length - 12);

		// 比较digest和digestWithSalt
		if (Arrays.equals(digest, digestWithSalt)) {

			flag = true;

		} else {

			flag = false;

		}

		return flag;
	}

	/**
	 *
     * Function:(密码加密前)检查密码的长度是否大于或等于 length,如果密码是null返回false
	 * @param password
	 * @param length
	 * @return
     * Create author:luojunlin
     * Create on:${date}
     * Edit author:
     * Edit on:
     * Why:
	 */
	public static boolean validatePWDLength(String password, int length) {
		return password != null ? password.length()>=length : false;
	}

	/**
	 *
     * Function:(密码加密前)检查密码的长度是否大于或等于 6,如果密码是null返回false
	 * @param password
	 * @return
     * Create author:luojunlin
     * Create on:${date}
     * Edit author:
     * Edit on:
     * Why:
	 */
	public static boolean validatePWDLength(String password) {
		int length=6;
		return password != null ? password.length()>=length : false;
	}

	/**
	 *
	 * Function:(密码加密前)检查密码的复杂度，如果满足复杂性策略，则返回真
	 * 复杂性策略：1.密码必须至少包含 6 个字符。
	 * 			 2.密码必须至少包含下列四类字符中的三类：1)大写字母[A-Z] 2)小写字母[a-z] 3)阿拉伯数字 \d 4)非字母数字 \W
	 * @param password
	 * @return
     * Create author:luojunlin
     * Create on:${date}
     * Edit author:
     * Edit on:
     * Why:
	 */
	public static boolean validatePWDComplicacy(String password){

		boolean result=false;

		if (validatePWDLength(password)) {
			int temp=0;
			temp = (Pattern.matches("\\S*[a-z]+\\S*", password) ? 1 : 0);
			temp += (Pattern.matches("\\S*[A-Z]+\\S*", password) ? 1 : 0);
			temp += (Pattern.matches("\\S*\\d+\\S*", password) ? 1 : 0);
			temp += (Pattern.matches("\\S*\\W+\\S*", password) ? 1 : 0);
			result = (temp >= 3 ? true : false);
		}

		return result;
	}
	public static void main(String args[]) throws Exception {

		System.out.println("输入口令：");
		BufferedReader is1 = new BufferedReader(
				new InputStreamReader(System.in));
		String strPassword = is1.readLine();
		System.out.println("口令经过hash之后变成的结果，如果用户第一次注册时我们就把这个结果放在数据库中,\n"
				+ "以便以后用来检验用户是否有正确的口令。");
		System.out.println("结果为 : ");
		String hashvalue = PasswordAuthenticator.createPassword(strPassword,
				"SHA-1");
		System.out.println(hashvalue.length());
		System.out.println(hashvalue);

		System.out.println("\n请在这里输入口令  : "
				+ "\n如果口令不是原来那个，那么就返回false。否则，就true。");
		BufferedReader is2 = new BufferedReader(
				new InputStreamReader(System.in));
		String strPassword2 = is2.readLine();
		is2.close();
		// 这里就的hashvalue2我们令它等于hashvalue，就是为了检验口令是否正确。
		String hashvalue2 = hashvalue;
		boolean flag = PasswordAuthenticator.authenticatePassword(strPassword2,
				hashvalue2,"SHA-1");

		if (flag == true) {
			System.out.println("口令正确");
		} else {
			System.out.println("请注意，口令错误");

		}
	}
}